#include "calculateitem2testjson.h"
#include <stdexcept>

// 声明全局变量（这些应该在原始C++代码中已定义）
extern int gRuleMinBoxInLib;
extern int gRuleMinStdtimeInLib;
extern int gRuleAddPosSTD;

void CalculateItem2TestJson::initTestCase()
{
    qDebug() << "=== 初始化 CalculateItem_2 JSON测试 ===";

    testDataFileBase = getTestDataBasePath();
    testResultFileBase = getTestResultBasePath();

    qDebug() << "测试数据基础路径:" << testDataFileBase;
    qDebug() << "测试结果基础路径:" << testResultFileBase;

    QDir testDataDir(testDataFileBase);
    if (!testDataDir.exists()) {
        qFatal("❌ 测试数据目录不存在: %s", testDataFileBase.toUtf8().constData());
    }

    QDir testResultDir(testResultFileBase);
    if (!testResultDir.exists()) {
        if (testResultDir.mkpath(".")) {
            qDebug() << "✅ 测试结果目录创建成功";
        } else {
            qWarning() << "❌ 测试结果目录创建失败";
        }
    }

    qDebug() << "✅ CalculateItem_2 JSON测试环境初始化完成";
}

QString CalculateItem2TestJson::getTestDataBasePath()
{
    QDir currentDir(QDir::currentPath());
    QDir targetDir = currentDir.filePath("../../../../../test_data");
    QString absolutePath = targetDir.absolutePath() + "/";

    if (targetDir.exists()) {
        qDebug() << "✅ 使用相对路径找到测试数据:" << absolutePath;
        return absolutePath;
    } else {
        qWarning() << "❌ 相对路径找不到测试数据，使用硬编码路径";
        return "D:/Work/algorithm-test/test_data/";
    }
}

QString CalculateItem2TestJson::getTestResultBasePath()
{
    QDir currentDir(QDir::currentPath());
    QDir targetDir = currentDir.filePath("../../../../../test_result");
    QString absolutePath = targetDir.absolutePath() + "/";

    if (targetDir.exists()) {
        qDebug() << "✅ 使用相对路径找到测试结果路径:" << absolutePath;
        return absolutePath;
    } else {
        if (targetDir.mkpath(".")) {
            qDebug() << "✅ 创建测试结果路径:" << absolutePath;
            return absolutePath;
        } else {
            qWarning() << "❌ 无法创建测试结果路径，使用硬编码路径";
            return "D:/Work/algorithm-test/test_result/";
        }
    }
}

QJsonObject CalculateItem2TestJson::readJsonObject(const QString& filePath)
{
    qDebug() << "读取JSON对象文件:" << filePath;

    QFile file(filePath);
    if (!file.open(QIODevice::ReadOnly)) {
        QString errorMsg = QString("无法打开文件：%1").arg(filePath);
        qWarning() << errorMsg;
        throw std::runtime_error(errorMsg.toStdString());
    }

    QByteArray data = file.readAll();
    file.close();

    QJsonDocument doc = QJsonDocument::fromJson(data);
    if (doc.isNull()) {
        qWarning() << "JSON解析失败，文件内容:" << QString(data).left(100) << "...";
        throw std::runtime_error("JSON解析失败");
    }

    if (!doc.isObject()) {
        qWarning() << "JSON不是对象格式";
        throw std::runtime_error("JSON不是对象格式");
    }

    return doc.object();
}

QJsonArray CalculateItem2TestJson::readJsonArray(const QString& filePath)
{
    qDebug() << "读取JSON数组文件:" << filePath;

    QFile file(filePath);
    if (!file.open(QIODevice::ReadOnly)) {
        QString errorMsg = QString("无法打开文件：%1").arg(filePath);
        qWarning() << errorMsg;
        throw std::runtime_error(errorMsg.toStdString());
    }

    QByteArray data = file.readAll();
    file.close();

    QJsonDocument doc = QJsonDocument::fromJson(data);
    if (doc.isNull()) {
        qWarning() << "JSON解析失败，文件内容:" << QString(data).left(100) << "...";
        throw std::runtime_error("JSON解析失败");
    }

    if (!doc.isArray()) {
        qWarning() << "JSON不是数组格式";
        throw std::runtime_error("JSON不是数组格式");
    }

    return doc.array();
}

void CalculateItem2TestJson::createFileRecursion(const QString& fileName)
{
    QFileInfo fileInfo(fileName);
    QDir dir = fileInfo.absoluteDir();

    if (!dir.exists()) {
        dir.mkpath(".");
    }

    QFile file(fileName);
    if (!file.exists()) {
        file.open(QIODevice::WriteOnly);
        file.close();
    }
}

void CalculateItem2TestJson::loadTestData(const QString& folderPath, CSchProcessPosition& processor)
{
    qDebug() << "加载测试数据:" << folderPath;
    
    try {
        // 1. 加载系统参数 hParamSet.json
        QJsonObject hParamSet = readJsonObject(folderPath + "hParamSet.json");
        qDebug() << "加载系统参数数量:" << hParamSet.keys().size();
        
        // 设置全局变量
        if (hParamSet.contains("MinInLibBoxPer")) {
            QJsonObject param = hParamSet["MinInLibBoxPer"].toObject();
            QString value = param["paramDefaultValue"].toString();
            gRuleMinBoxInLib = value.toInt();
            qDebug() << "设置 gRuleMinBoxInLib =" << gRuleMinBoxInLib;
        }

        if (hParamSet.contains("MinInLibSTDPer")) {
            QJsonObject param = hParamSet["MinInLibSTDPer"].toObject();
            QString value = param["paramDefaultValue"].toString();
            gRuleMinStdtimeInLib = value.toInt();
            qDebug() << "设置 gRuleMinStdtimeInLib =" << gRuleMinStdtimeInLib;
        }
        
        if (hParamSet.contains("AddPosSTD")) {
            QJsonObject param = hParamSet["AddPosSTD"].toObject();
            QString value = param["paramDefaultValue"].toString();
            gRuleAddPosSTD = value.toInt();
            qDebug() << "设置 gRuleAddPosSTD =" << gRuleAddPosSTD;
        }

        // 设置processor.pSchData中的参数
        processor.pSchData->hParamSet.clear();
        for (auto it = hParamSet.begin(); it != hParamSet.end(); ++it) {
            QString paramName = it.key();
            QJsonObject paramObj = it.value().toObject();
            CSysParamData* paramData = new CSysParamData();
            paramData->mDefaultValue = paramObj["paramDefaultValue"].toString();
            paramData->mValue = paramObj["paramDefaultValue"].toString();
            processor.pSchData->hParamSet[paramName] = paramData;
        }

        // 2. 加载工序集 hProcessSet.json
        QJsonObject hProcessSet = readJsonObject(folderPath + "hProcessSet.json");
        qDebug() << "加载工序集数量:" << hProcessSet.keys().size();
        qDebug() << "工序集内容预览:" << hProcessSet.keys().first() << "=" << hProcessSet.value(hProcessSet.keys().first()).toObject().value("orderProcessId");
        
        // 清空并设置工序集
        processor.ProcessPosition.hProcessSet.clear();
        // 解析JSON并创建工序对象
        for (auto it = hProcessSet.begin(); it != hProcessSet.end(); ++it) {
            qlonglong processId = it.key().toLongLong();
            QJsonObject processObj = it.value().toObject();
            
            // 创建工序对象
            CJgOrderProcess* process = new CJgOrderProcess();
            process->miProcessId = processObj["orderProcessId"].toVariant().toLongLong();
            process->mfProcessTotalTime = processObj["mfProcessTotalTime"].toDouble();
            process->mfProcessStdTime = processObj["mfProcessTotalTime"].toDouble(); // 使用总工时作为标准工时
            process->miFinishedCnt = processObj["miFinishedCnt"].toInt();
            process->mbCompletedFlag = processObj["mbCompletedFlag"].toBool();
            process->miPartSeqNum = processObj["miPartSeqNum"].toInt();
            
            // 创建订单对象
            process->pOrder = new CJgOrder();
            process->pOrder->miNow2DeadlineSecs = processObj["miNow2DeadlineSecs"].toInt();
            
            // 创建调度对象
            process->mScheduling = new CJgProcessSchedule();
            QJsonObject schedulingObj = processObj["mscheduling"].toObject();
            process->mScheduling->mbHoldFlag = schedulingObj["mbHoldFlag"].toBool();
            process->mScheduling->mbNGFlag = schedulingObj["mbNGFlag"].toBool();
            process->mScheduling->mbAllUnDoInLib = schedulingObj["mbAllUnDoInLib"].toBool();
            process->mScheduling->mNowHourTarget = schedulingObj["mnowHourTarget"].toInt();
            
            // 设置在库筐信息
            QJsonObject boxesInLibObj = schedulingObj["mboxesInLib"].toObject();
            process->mScheduling->mBoxesInLib.miBoxCnt = boxesInLibObj["miBoxCnt"].toInt();
            process->mScheduling->mBoxesInLib.miCutCnt = boxesInLibObj["miCutCnt"].toInt();
            
            // 设置在产筐信息
            QJsonObject boxesInWorkObj = schedulingObj["mboxesInWork"].toObject();
            process->mScheduling->mBoxesInWork.miBoxCnt = boxesInWorkObj["miBoxCnt"].toInt();
            process->mScheduling->mBoxesInWork.miCutCnt = boxesInWorkObj["miCutCnt"].toInt();
            
            processor.ProcessPosition.hProcessSet.insert(processId, process);
        }
        
        // 3. 加载可排产的工位 sPositionsScore.json
        QJsonArray sPositionsScore = readJsonArray(folderPath + "sPositionsScore.json");
        qDebug() << "加载可排产工位数量:" << sPositionsScore.size();
        qDebug() << "可排产工位预览:" << sPositionsScore.first() << "," << sPositionsScore.last();
        
        // 清空并设置可排产工位
        processor.ProcessPosition.sPositionsScore.clear();
        for (const QJsonValue& value : sPositionsScore) {
            processor.ProcessPosition.sPositionsScore.insert(value.toInt());
        }
        
        // 4. 加载订单映射数据 orderId2Order.json
        QJsonObject orderId2Order = readJsonObject(folderPath + "orderId2Order.json");
        qDebug() << "加载订单映射数据数量:" << orderId2Order.keys().size();
        
        // 5. 加载按工序查找的分数表 hScoreByProcess.json
        QJsonObject hScoreByProcess = readJsonObject(folderPath + "hScoreByProcess.json");
        qDebug() << "加载分数表工序数量:" << hScoreByProcess.keys().size();
        qDebug() << "分数表工序预览:" << hScoreByProcess.keys().first();
        
        // 清空并设置分数表
        processor.ProcessPosition.hScoreByProcess.clear();
        // 解析JSON并创建分数对象
        for (auto it = hScoreByProcess.begin(); it != hScoreByProcess.end(); ++it) {
            qlonglong processId = it.key().toLongLong();
            QJsonArray scoresArray = it.value().toArray();
            
            QVector<SSCORE*> scores;
            for (int i = 0; i < scoresArray.size(); ++i) {
                QJsonObject scoreObj = scoresArray[i].toObject();
                SSCORE* score = new SSCORE();
                score->ProcessID = processId;
                score->Position = scoreObj["positionId"].toInt();
                score->Total = scoreObj["total"].toDouble(); // 从JSON读取Total值
                
                // 从JSON读取ScoreItem数组
                QJsonArray scoreItemArray = scoreObj["scoreItem"].toArray();
                for (int j = 0; j < _MAX_SCORE_ITEM_ && j < scoreItemArray.size(); ++j) {
                    score->ScoreItem[j] = scoreItemArray[j].toDouble();
                }
                // 如果JSON中的scoreItem数组小于_MAX_SCORE_ITEM_，则其余部分保持为0
                for (int j = scoreItemArray.size(); j < _MAX_SCORE_ITEM_; ++j) {
                    score->ScoreItem[j] = 0.0;
                }
                
                // 关联工序对象
                if (processor.ProcessPosition.hProcessSet.contains(processId)) {
                    score->pOp = processor.ProcessPosition.hProcessSet[processId];
                }
                
                scores.append(score);
            }
            
            processor.ProcessPosition.hScoreByProcess.insert(processId, scores);
        }
        
        // 建立工序和工位之间的关联
        for (auto it = processor.ProcessPosition.hProcessSet.begin(); 
             it != processor.ProcessPosition.hProcessSet.end(); ++it) {
            CJgOrderProcess* process = it.value();
            // 为每个工序添加所有可排产的工位到可执行工位列表中
            for (int position : processor.ProcessPosition.sPositionsScore) {
                process->mScheduling->mPosCanDo.append(position);
            }
        }
        
        // 输出当前processor的状态
        qDebug() << "processor.ProcessPosition.hProcessSet.size():" << processor.ProcessPosition.hProcessSet.size();
        qDebug() << "processor.ProcessPosition.sPositionsScore.size():" << processor.ProcessPosition.sPositionsScore.size();
        qDebug() << "processor.ProcessPosition.hScoreByProcess.size():" << processor.ProcessPosition.hScoreByProcess.size();
        
        // 调试输出：检查关键条件
        for (auto it = processor.ProcessPosition.hProcessSet.begin(); 
             it != processor.ProcessPosition.hProcessSet.end(); ++it) {
            CJgOrderProcess* process = it.value();
            qDebug() << "Process ID:" << process->miProcessId 
                     << "mbHoldFlag:" << process->mScheduling->mbHoldFlag
                     << "mbNGFlag:" << process->mScheduling->mbNGFlag
                     << "mbAllUnDoInLib:" << process->mScheduling->mbAllUnDoInLib
                     << "miBoxCnt:" << process->mScheduling->mBoxesInLib.miBoxCnt
                     << "miCutCnt:" << process->mScheduling->mBoxesInLib.miCutCnt;
        }
        
        // 额外验证：确保所有工序在hScoreByProcess中都有对应条目
        // 这可以防止在CalculateItem_2中访问不存在的键时出现QHash断言失败
        for (auto it = processor.ProcessPosition.hProcessSet.begin(); 
             it != processor.ProcessPosition.hProcessSet.end(); ++it) {
            qlonglong processId = it.key();
            if (!processor.ProcessPosition.hScoreByProcess.contains(processId)) {
                // 如果hScoreByProcess中没有该工序，则创建一个空的分数向量
                QVector<SSCORE*> emptyScores;
                processor.ProcessPosition.hScoreByProcess.insert(processId, emptyScores);
                qDebug() << "警告：为工序ID" << processId << "添加了空的分数条目";
            }
        }
        
    } catch (const std::exception& e) {
        qWarning() << "加载测试数据失败:" << e.what();
        throw;
    }
}

void CalculateItem2TestJson::testSingleCase(const QString& folderPath, const QString& resultFileName)
{
    qDebug() << "测试用例路径:" << folderPath;

    try {
        // 1. 创建 CSchProcessPosition 实例
        CSchProcessPosition schProcessPosition;
        schProcessPosition.pSchData = new SSCHDATAINPUT();
        
        // 2. 加载测试数据
        loadTestData(folderPath, schProcessPosition);
        
        // 3. 读取函数参数
        QJsonObject functionParams = readJsonObject(folderPath + "testCases.json");
        double ratio = functionParams["ratio"].toDouble();
        qDebug() << "测试参数 ratio:" << ratio;

        // 4. 调用 CalculateItem_2 方法前的状态
        qDebug() << "调用CalculateItem_2前的processor状态:";
        qDebug() << "  hProcessSet.size():" << schProcessPosition.ProcessPosition.hProcessSet.size();
        qDebug() << "  sPositionsScore.size():" << schProcessPosition.ProcessPosition.sPositionsScore.size();
        qDebug() << "  hScoreByProcess.size():" << schProcessPosition.ProcessPosition.hScoreByProcess.size();
        
        // 更详细的调试信息
        for (auto it = schProcessPosition.ProcessPosition.hProcessSet.begin(); 
             it != schProcessPosition.ProcessPosition.hProcessSet.end(); ++it) {
            CJgOrderProcess* process = it.value();
            qDebug() << "  工序ID:" << process->miProcessId 
                     << "mbHoldFlag:" << process->mScheduling->mbHoldFlag
                     << "mbNGFlag:" << process->mScheduling->mbNGFlag
                     << "mbAllUnDoInLib:" << process->mScheduling->mbAllUnDoInLib;
        }
        
        for (auto it = schProcessPosition.ProcessPosition.hScoreByProcess.begin(); 
             it != schProcessPosition.ProcessPosition.hScoreByProcess.end(); ++it) {
            qDebug() << "  分数表工序ID:" << it.key() << "包含分数数量:" << it.value().size();
        }

        // 5. 调用 CalculateItem_2 方法
        qDebug() << "调用 CalculateItem_2 方法，参数 ratio=" << ratio;
        try {
            schProcessPosition.CalculateItem_2(static_cast<float>(ratio));
            qDebug() << "CalculateItem_2 方法执行完成";
        } catch (const std::exception& e) {
            qWarning() << "CalculateItem_2 执行异常:" << e.what();
            throw;
        } catch (...) {
            qWarning() << "CalculateItem_2 执行未知异常";
            throw;
        }

        // 6. 调用 CalculateItem_2 后的状态
        qDebug() << "调用CalculateItem_2后的processor状态:";
        qDebug() << "  hProcessSet.size():" << schProcessPosition.ProcessPosition.hProcessSet.size();
        qDebug() << "  sPositionsScore.size():" << schProcessPosition.ProcessPosition.sPositionsScore.size();
        qDebug() << "  hScoreByProcess.size():" << schProcessPosition.ProcessPosition.hScoreByProcess.size();

        // 7. 写入结果文件
        createFileRecursion(resultFileName);
        QFile resultFile(resultFileName);
        if (resultFile.open(QIODevice::WriteOnly | QIODevice::Text)) {
            QTextStream stream(&resultFile);
            
            // 输出处理后的分数信息
            // 遍历 hScoreByProcess 输出结果（按键排序）
            const QHash<qlonglong, QVector<SSCORE*>>& scoreByProcess = schProcessPosition.getScoreByProcess();
            bool hasData = false;
            qDebug() << "scoreByProcess.size():" << scoreByProcess.size();
            
            // 获取所有键并排序
            QList<qlonglong> keys = scoreByProcess.keys();
            std::sort(keys.begin(), keys.end());
            
            // 按排序后的键顺序输出
            for (qlonglong processId : keys) {
                QVector<SSCORE*> scores = scoreByProcess[processId];
                
                stream << "Process ID: " << processId << "\n";
                qDebug() << "Process ID:" << processId << "Scores count:" << scores.size();
                
                for (SSCORE* score : scores) {
                    stream << "  Position ID: " << score->Position
                           << ", Total Score: " << QString::number(score->Total, 'f', 4)
                           << ", Score Item [1]: " << QString::number(score->ScoreItem[1], 'f', 4) << "\n";
                    hasData = true;
                    qDebug() << "  Position ID:" << score->Position 
                             << ", Total Score:" << QString::number(score->Total, 'f', 4)
                             << ", Score Item [1]:" << QString::number(score->ScoreItem[1], 'f', 4);
                }
            }
            
            if (!hasData) {
                stream << "无数据输出\n";
                qDebug() << "无数据输出";
            }
            
            resultFile.close();
            qDebug() << "结果写入:" << resultFileName;
        }

    } catch (const std::exception& e) {
        qWarning() << "测试用例执行失败:" << e.what();
        // 写入错误结果
        createFileRecursion(resultFileName);
        QFile resultFile(resultFileName);
        if (resultFile.open(QIODevice::WriteOnly | QIODevice::Text)) {
            QTextStream stream(&resultFile);
            stream << "测试失败: " << e.what() << "\n";
            resultFile.close();
        }
    }
}

void CalculateItem2TestJson::testCalculateItem2FromJson()
{
    qDebug() << "=== 开始使用JSON数据测试 CalculateItem_2 方法 ===";

    // 遍历测试用例
    for (int i = 1; i <= 52; i++) {
        try {
            QString folderPath;
            QString resultFileName;

            if (i <= 50) {
                folderPath = testDataFileBase + QString("calculateItem_2/random_case_%1/").arg(i);
                resultFileName = testResultFileBase + QString("calculateItem_2_c/random_case_%1.txt").arg(i);
            } else {
                folderPath = testDataFileBase + QString("calculateItem_2/manual_case_%1/").arg(i - 50);
                resultFileName = testResultFileBase + QString("calculateItem_2_c/manual_case_%1.txt").arg(i - 50);
            }

            QDir folder(folderPath);
            if (!folder.exists()) {
                qWarning() << "文件夹不存在：" << folderPath;
                continue;
            }

            qDebug() << "\n=== 处理测试用例" << (i <= 50 ? "random_case_" : "manual_case_") << (i <= 50 ? i : (i - 50)) << "===";

            // 测试单个用例
            testSingleCase(folderPath, resultFileName);

            qDebug() << "测试完成:" << (i <= 50 ? "random_case_" : "manual_case_") << (i <= 50 ? i : (i - 50));

        } catch (const std::exception& e) {
            qWarning() << "测试失败:" << (i <= 50 ? "random_case_" : "manual_case_") << (i <= 50 ? i : (i - 50)) << "错误:" << e.what();
        }
    }
}

void CalculateItem2TestJson::cleanupTestCase()
{
    qDebug() << "清理 CalculateItem_2 JSON测试用例...";
}
